package com.sinodata.bsm.cicp.collector.net.collector;

import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.log4j.Logger;
import org.snmp4j.smi.VariableBinding;
import org.snmp4j.util.TableEvent;

import com.adventnet.snmp.mibs.MibNode;
import com.sinodata.bsm.cicp.collector.Collector;
import com.sinodata.bsm.cicp.exception.CollectorException;
import com.sinodata.bsm.common.vo.ResPropertyValue;
import com.union.net.discovery.agent.Interfaces.IfEntry;
import com.union.net.snmp.SnmpGet;
import com.union.net.utils.MibUtil;

public class NetinterfacesCollector extends Collector {
    private static Logger logger = Logger.getLogger(NetinterfacesCollector.class.getName());
    long timeOut = 1 * 60 * 1000;
    private static Map<String, Object> lockMap = new HashMap<String, Object>();
    Object syncObj;

    public List<ResPropertyValue> collect(String ip) throws CollectorException {
        synchronized (lockMap) {
            syncObj = lockMap.get(ip);
            if (syncObj == null) {
                syncObj = new Object();
                lockMap.put(ip, syncObj);
            }
        }
        //        String ipString = this.paramMap.get("IP");
        String ifIndex = this.getParamMap().get("接口索引");
        String community = this.getParamMap().get("共同体");

        IfIndexInfo ifIndexInfo;
        List<ResPropertyValue> values = new ArrayList<ResPropertyValue>();
        try {
            synchronized (syncObj) {
                ifIndexInfo = (IfIndexInfo) getPersistentData("interface" + ip);// 获取上次采集数据
                if (ifIndexInfo == null) {
                    this.getValuesMap(ip, community);
                    return null;
                }

                long lastTime = ifIndexInfo.timeStamp;

                String[] propMetas = getPropMeta();

                ResPropertyValue propertyValueX = new ResPropertyValue();
                ResPropertyValue.PropValue[] propValues = new ResPropertyValue.PropValue[propMetas.length];

                if (System.currentTimeMillis() - lastTime > timeOut) {
                    this.getValuesMap(ip, community);
                }
                IfInterfaceInfo ifInterfaceInfo = ((NetInterfaceVo) getPersistentData("value" + ip)).getIfIntervalues().get(ip + ":" + ifIndex);

                if (ifInterfaceInfo.getIfInVelocity() < 0 || ifInterfaceInfo.getIfOutVelocity() < 0) {
                    return null;
                }

                propValues[0] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfInVelocity() + "", propMetas[0]);
                propValues[1] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfOutVelocity() + "", propMetas[1]);
                propValues[2] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfStatus(), propMetas[2]);
                propValues[3] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfLastChange(), propMetas[3]);
                propValues[4] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfInOctets(), propMetas[4]);
                propValues[5] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfOutOctets(), propMetas[5]);
                propValues[6] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfInDiscards(), propMetas[6]);
                propValues[7] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfInErrors(), propMetas[7]);
                propValues[8] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfOutDiscards(), propMetas[8]);
                propValues[9] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfOutErrors(), propMetas[9]);
                propValues[10] = ResPropertyValue.createPropValue(ifInterfaceInfo.getIfOutQLen(), propMetas[10]);

                propertyValueX.setValues(propValues);
                values.add(propertyValueX);
            }
        } catch (Exception e) {
            logger.error(e);
            throw new CollectorException(e);
        }

        return values;
    }

    private void getValuesMap(String ip, String community) {
        SnmpGet get = null;
        Map<String, IfEntry> ifEntryMaps = new HashMap<String, IfEntry>();
        Map<String, IfInterfaceInfo> ifIntervalues = new HashMap<String, IfInterfaceInfo>();
        NetInterfaceVo netInterfaceVo = new NetInterfaceVo();
        try {
            get = new SnmpGet(ip);
            get.setCommunity(community);
            //			 if (!get.testManageable())
            //			 return ;
            List<IfEntry> ifTable = new ArrayList<IfEntry>();
            setValues(get, ifTable, IfEntry.class, "1.3.6.1.2.1.2.2");
            for (int i = 0; i < ifTable.size(); i++) {
                IfInterfaceInfo ifInterfaceInfo = new IfInterfaceInfo();
                long ifInVelocity = 0; // 接口输入速度
                long ifOutVelocity = 0;// 接口输出速度
                String ifStatus = ""; // 接口状态
                IfEntry ifEntry = ifTable.get(i);
                String ifIndex = ifEntry.getIfIndex(); // 接口标识
                String ifInOctets = ifEntry.getIfInOctets();// 接口输入
                String ifOutOctets = ifEntry.getIfOutOctets();// 接口输出
                String ifOperStatus = ifEntry.getIfOperStatus();// 接口状态
                String ifInDiscards = ifEntry.getIfInDiscards();//入丢包数
                String ifInErrors = ifEntry.getIfInErrors();//入错包数
                String ifOutDiscards = ifEntry.getIfOutDiscards();//出丟包數
                String ifOutErrors = ifEntry.getIfOutErrors();//出错包数
                String ifOutQLen = ifEntry.getIfOutQLen();//出包队列长度
                String ifLastChange = ifEntry.getIfLastChange();//最后改变时间
                if (ifLastChange == null)
                    ifLastChange = "0";

                IfIndexInfo ifIndexInfo = (IfIndexInfo) getPersistentData("interface" + ip);// 获取上次采集数据
                if (null != ifIndexInfo) {
                    long lastTime = ifIndexInfo.timeStamp;
                    Map<String, IfEntry> ifEntryolds = ifIndexInfo.values;
                    IfEntry lastIfEntry = ifEntryolds.get(ip + ifIndex);
                    //                    String lastIfIndex = lastIfEntry.getIfIndex(); // 历史接口标识
                    String lastIfInOctets = lastIfEntry.getIfInOctets();// 历史接口输入
                    String lastIfOutOctets = lastIfEntry.getIfOutOctets();// 历史接口输出
                    //                    String lastIfOperStatus = lastIfEntry.getIfOperStatus();// 历史接口状态
                    if ((System.currentTimeMillis() - lastTime) / 1000 == 0) {
                        ifInVelocity = 0;
                        ifOutVelocity = 0;
                    } else {
                        ifInVelocity = ((Long.parseLong(ifInOctets) - Long.parseLong(lastIfInOctets)) / 1024) / ((System.currentTimeMillis() - lastTime) / 1000); //入流速

                        ifOutVelocity = ((Long.parseLong(ifOutOctets) - Long.parseLong(lastIfOutOctets)) / 1024) / ((System.currentTimeMillis() - lastTime) / 1000); //出流速
                    }
                    //					ifStatus = lastIfOperStatus;

                }
                //				接口 状态
                //				up (1)
                //				down (2)
                //				testing (3)
                //				unknown (4)
                //				dormant (5)
                //				notPresent (6)
                //				lowerLayerDown (7)
                if (ifOperStatus.equals("1")) {
                    ifStatus = "up";
                } else if (ifOperStatus.equals("2")) {
                    ifStatus = "down";
                } else if (ifOperStatus.equals("3")) {
                    ifStatus = "testing";
                } else if (ifOperStatus.equals("4")) {
                    ifStatus = "unknown";
                } else if (ifOperStatus.equals("5")) {
                    ifStatus = "dormant";
                } else if (ifOperStatus.equals("6")) {
                    ifStatus = "notPresent";
                } else if (ifOperStatus.equals("7")) {
                    ifStatus = "lowerLayerDown";
                }

                ifInterfaceInfo.setIfLastChange(ifLastChange);
                ifInterfaceInfo.setIfStatus(ifStatus);
                ifInterfaceInfo.setIfInDiscards(ifInDiscards);
                ifInterfaceInfo.setIfInErrors(ifInErrors);
                ifInterfaceInfo.setIfInOctets(ifInOctets);
                ifInterfaceInfo.setIfInVelocity(ifInVelocity);
                ifInterfaceInfo.setIfOutDiscards(ifOutDiscards);
                ifInterfaceInfo.setIfOutErrors(ifOutErrors);
                ifInterfaceInfo.setIfOutOctets(ifOutOctets);
                ifInterfaceInfo.setIfOutQLen(ifOutQLen);
                ifInterfaceInfo.setIfOutVelocity(ifOutVelocity);
                ifIntervalues.put(ip + ":" + ifIndex, ifInterfaceInfo);
                ifEntryMaps.put(ip + ifIndex, ifEntry);
            }
            netInterfaceVo.setIfIntervalues(ifIntervalues);
            savePersistentData("value" + ip, netInterfaceVo);
            IfIndexInfo ifIndexInfo = new IfIndexInfo();
            ifIndexInfo.timeStamp = System.currentTimeMillis();
            ifIndexInfo.values = ifEntryMaps;
            savePersistentData("interface" + ip, ifIndexInfo);
        } catch (IOException e) {
            logger.error(" ", e);
        } catch (Exception e) {
            logger.error(" ", e);
        } finally {
            get.close();
        }
    }

    private void setValues(SnmpGet get, List object, Class<? extends Object> t, String oidsrc) throws Exception {
        List<TableEvent> table = get.getTable(oidsrc);
        Map<String, Object> entityMap = new HashMap<String, Object>();

        for (TableEvent tableEvent : table) {
            if (tableEvent == null || tableEvent.getColumns() == null) {
                logger.info("oid:" + oidsrc + " tableEvent:" + tableEvent + " size:" + table.size());
                continue;
            }
            VariableBinding variable = tableEvent.getColumns()[0];
            String oid = variable.getOid().toString();
            String value = variable.getVariable().toString();
            MibNode node = MibUtil.getMibNode(oid);
            String label = node.getLabel();
            String oidNumber = node.getNumberedOIDString();
            String syntax = node.getSyntax().getName();
            String index = oid.substring(oidNumber.length() - 1);
            Object element;
            if (!entityMap.containsKey(index)) {
                element = t.newInstance();
                entityMap.put(index, element);
                object.add(element);
            } else {
                element = entityMap.get(index);
            }
            logger.debug(String.format("oid:%s value:%s nodeName:%s sybtax:%s miboid:%s count:%d", oid, value, label, syntax, oidNumber, tableEvent.getColumns().length));
            try {
                BeanUtils.setProperty(element, label, value);
            } catch (Exception e) {
                logger.warn(label, e);
            }

        }
        //		 logger.debug(object.toString());
    }

    public String[] getParamMeta() {
        return new String[] { "接口IP", "接口索引", "共同体" };
    }

    public String[] getPropMeta() {
        return new String[] { "入流速", "出流速", "接口状态", "最后改变时间", "接口输入", "接口输出", "入丢包数", "入错包数", "出丢包数", "出错包数", "出包队列长度" };
    }

    static class IfIndexInfo implements Serializable {
        /**
         *
         */
        private static final long serialVersionUID = -7742689392523886778L;
        long timeStamp = System.currentTimeMillis();
        Map<String, IfEntry> values = null;
    }

    static class IfInterfaceInfo implements Serializable {
        /**
         *
         */
        private static final long serialVersionUID = 8183659263171325334L;
        String ifLastChange;
        long ifInVelocity;
        long ifOutVelocity;
        String ifStatus;
        String ifInOctets;
        String ifOutOctets;
        String ifInDiscards;
        String ifInErrors;
        String ifOutDiscards;
        String ifOutErrors;
        String ifOutQLen;

        public String getIfInOctets() {
            return ifInOctets;
        }

        public void setIfInOctets(String ifInOctets) {
            this.ifInOctets = ifInOctets;
        }

        public String getIfOutOctets() {
            return ifOutOctets;
        }

        public void setIfOutOctets(String ifOutOctets) {
            this.ifOutOctets = ifOutOctets;
        }

        public String getIfInDiscards() {
            return ifInDiscards;
        }

        public void setIfInDiscards(String ifInDiscards) {
            this.ifInDiscards = ifInDiscards;
        }

        public String getIfInErrors() {
            return ifInErrors;
        }

        public void setIfInErrors(String ifInErrors) {
            this.ifInErrors = ifInErrors;
        }

        public String getIfOutDiscards() {
            return ifOutDiscards;
        }

        public void setIfOutDiscards(String ifOutDiscards) {
            this.ifOutDiscards = ifOutDiscards;
        }

        public String getIfOutErrors() {
            return ifOutErrors;
        }

        public void setIfOutErrors(String ifOutErrors) {
            this.ifOutErrors = ifOutErrors;
        }

        public String getIfOutQLen() {
            return ifOutQLen;
        }

        public void setIfOutQLen(String ifOutQLen) {
            this.ifOutQLen = ifOutQLen;
        }

        public long getIfInVelocity() {
            return ifInVelocity;
        }

        public void setIfInVelocity(long ifInVelocity) {
            this.ifInVelocity = ifInVelocity;
        }

        public long getIfOutVelocity() {
            return ifOutVelocity;
        }

        public void setIfOutVelocity(long ifOutVelocity) {
            this.ifOutVelocity = ifOutVelocity;
        }

        public String getIfStatus() {
            return ifStatus;
        }

        public void setIfStatus(String ifStatus) {
            this.ifStatus = ifStatus;
        }

        public String getIfLastChange() {
            return ifLastChange;
        }

        public void setIfLastChange(String ifLastChange) {
            this.ifLastChange = ifLastChange;
        }
    }

    static class NetInterfaceVo implements Serializable {
        /**
         *
         */
        private static final long serialVersionUID = 3529008917735640439L;
        private Map<String, IfInterfaceInfo> ifIntervalues = new HashMap<String, IfInterfaceInfo>();

        public Map<String, IfInterfaceInfo> getIfIntervalues() {
            return ifIntervalues;
        }

        public void setIfIntervalues(Map<String, IfInterfaceInfo> ifIntervalues) {
            this.ifIntervalues = ifIntervalues;
        }
    }

}
